﻿using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Globalization;
using System;

namespace JsonCreator
{
    internal static class jsonManager
    {
        public static string Folder { get; private set; }
        public static string GetFilePath(string file)
        {
            return Path.Combine(Folder, Path.ChangeExtension(file, ".jpg"));
        }


        private static Dictionary<string, JsonCreator.foto> albumKey = new Dictionary<string, JsonCreator.foto>();
        public static LinkedList<JsonCreator.foto> Album = new LinkedList<foto>();

        public static void Clear()
        {
            albumKey.Clear();
            Album.Clear();
        }

        public static JsonCreator.foto GetFoto(string filename)
        {
            return albumKey.ContainsKey(filename)
                        ? albumKey[filename]
                        : null;
        }

        public static void PutFoto(foto myfoto)
        {
            if (!albumKey.ContainsKey(myfoto.filename))
            {
                Album.AddLast(myfoto);
                albumKey.Add(myfoto.filename, myfoto);
            }
        }

        public static void DeserializeJSon(string folder)
        {
            string file = Path.Combine(folder, "images.js");
            Folder = folder;

            fastJSON.JSON.Instance.Parameters.SerializeNullValues = false;
            fastJSON.JSON.Instance.Parameters.UseExtensions=false;
            fastJSON.JSON.Instance.Parameters.EnableAnonymousTypes = true;

            if (File.Exists(file))
            {
                using (StreamReader sr = new StreamReader(file))
                {
                    string fileData = sr.ReadToEnd();
                    sr.Close();
                    //Album = fastJSON.JSON.Instance.ToObject<LinkedList<JsonCreator.foto>>(fileData);
                    Album = (LinkedList<JsonCreator.foto>)fastJSON.JSON.Instance.ToObject(fileData, typeof(LinkedList<JsonCreator.foto>));
                }
                using (FileStream fs = new FileStream(file, FileMode.Open))
                {
                    var serializer = new DataContractJsonSerializer(typeof(LinkedList<JsonCreator.foto>));
                    Album = (LinkedList<JsonCreator.foto>)serializer.ReadObject(fs);
                    foreach (JsonCreator.foto myfoto in Album)
                        albumKey.Add(myfoto.filename, myfoto);
                }
            }
        }

        public static void LoadData(string folder)
        {
            DeserializeJSon(folder);
            string[] files = Directory.GetFiles(folder, "*.jpg");

            foreach (string file in files)
            {
                string key = Path.GetFileNameWithoutExtension(file);

                foto myPhoto = null;
                if (albumKey.ContainsKey(key))
                    myPhoto = albumKey[key];
                else
                {
                    myPhoto = CreateFoto(file);
                    Album.AddLast(myPhoto);
                    albumKey.Add(key, myPhoto);
                }
            }
        }

        public static void SaveData(string folder)
        {
            string file = Path.Combine(folder, "images.js");
            if (File.Exists(file))
                File.Delete(file);
            using (FileStream fs = new FileStream(file, FileMode.OpenOrCreate))
            {
                var serializer = new DataContractJsonSerializer(typeof(LinkedList<JsonCreator.foto>));
                serializer.WriteObject(fs, Album);
            }

            string val = fastJSON.JSON.Instance.ToJSON(Album, new fastJSON.JSONParameters { SerializeNullValues = false,  UseExtensions=false, EnableAnonymousTypes=true});
            using (StreamWriter sw = new StreamWriter(file))
            {
                sw.Write(val);
                sw.Close();
            }
        }


        private static foto CreateFoto(string file)
        {
            Fotofly.JpgPhoto pict = new Fotofly.JpgPhoto(file);

            foto myphoto = new foto();
            string peoples = string.Empty;
            foreach (string name in pict.Metadata.People)
                peoples = peoples.CommaConcact(name);

            foreach (Fotofly.Tag tag in pict.Metadata.Tags)
                DecodeTag(ref myphoto, tag);

            myphoto.filename = Path.GetFileNameWithoutExtension(file);
            myphoto.title = pict.Metadata.Description.NotNullValue();
            //myphoto.people = peoples;
            myphoto.comment = pict.Metadata.Subject.NotNullValue();
            myphoto.yeardate = pict.Metadata.DateDigitised.Year;
            myphoto.monthdate = pict.Metadata.DateDigitised.ToString("MMMM");
            myphoto.stars = pict.Metadata.Rating.Numerical;
            myphoto.lat = pict.Metadata.GpsPositionOfLocationCreated.Latitude.Numeric.CompareTo(double.NaN) == 0
                                ? string.Empty
                                : pict.Metadata.GpsPositionOfLocationCreated.Latitude.Numeric.ToString(CultureInfo.CreateSpecificCulture("en-US")).NotNullValue();
            myphoto.lon = pict.Metadata.GpsPositionOfLocationCreated.Longitude.Numeric.CompareTo(double.NaN) == 0
                                ? string.Empty
                                : pict.Metadata.GpsPositionOfLocationCreated.Longitude.Numeric.ToString(CultureInfo.CreateSpecificCulture("en-US")).NotNullValue();

            pict = null;

            return myphoto;
        }

        public static void UpdateFoto(ref foto myphoto)
        {
            string file = jsonManager.GetFilePath(myphoto.filename);
            Fotofly.JpgPhoto pict = new Fotofly.JpgPhoto(file);

            string peoples = string.Empty;
            foreach (string name in pict.Metadata.People)
                peoples = peoples.CommaConcact(name);

            foreach (Fotofly.Tag tag in pict.Metadata.Tags)
                DecodeTag(ref myphoto, tag);

            myphoto.filename = Path.GetFileNameWithoutExtension(file);
            myphoto.title = pict.Metadata.Description.NotNullValue();
            //myphoto.people = peoples;
            myphoto.comment = pict.Metadata.Subject.NotNullValue();
            myphoto.yeardate = pict.Metadata.DateDigitised.Year;
            myphoto.monthdate = pict.Metadata.DateDigitised.ToString("MMMM");
            myphoto.stars = pict.Metadata.Rating.Numerical;
            myphoto.lat = pict.Metadata.GpsPositionOfLocationCreated.Latitude.Numeric.ToString(CultureInfo.CreateSpecificCulture("en-US")).NotNullValue();
            myphoto.lon = pict.Metadata.GpsPositionOfLocationCreated.Longitude.Numeric.ToString(CultureInfo.CreateSpecificCulture("en-US")).NotNullValue();
        }

        public static void UpdateFile(foto myFoto)
        {
            string file = jsonManager.GetFilePath(myFoto.filename);

            Fotofly.JpgPhoto pict = new Fotofly.JpgPhoto(file);
            pict.Metadata.Description = myFoto.title.NotNullValue();
            pict.Metadata.Subject = myFoto.comment.NotNullValue();
            pict.Metadata.Tags.AddRange(EncodeTag(myFoto.events, myFoto.type, myFoto.place, myFoto.privates));
            pict.Metadata.Rating.Numerical = myFoto.stars;
            pict.WriteMetadata();
            pict = null;
        }

        private static Fotofly.TagList EncodeTag(string events, string type, string place, string privates)
        {
            Fotofly.TagList tl = new Fotofly.TagList();
            if (!string.IsNullOrEmpty(events))
                tl.Add(string.Concat("evento:", events));

            if (!string.IsNullOrEmpty(type))
                tl.Add(string.Concat("genere:", type));

            if (!string.IsNullOrEmpty(place))
                tl.Add(string.Concat("luogo:", place));

            if (!string.IsNullOrEmpty(privates))
                tl.Add(string.Concat("privata:", privates));

            return tl;

        }

        private static void DecodeTag(ref foto myFoto, Fotofly.Tag tag)
        {
            string[] splitTag = tag.Name.Split(':');
            for (int t = 0; t < splitTag.Length; t++)
                splitTag[t] = splitTag[t].Trim();

            switch (splitTag[0].ToLower())
            {
                case "evento":
                    myFoto.events = splitTag[1];
                    break;
                case "genere":
                    myFoto.type = splitTag[1];
                    break;
                case "luogo":
                    myFoto.place = splitTag[1];
                    break;
                case "privata":
                    myFoto.privates = splitTag[1];
                    break;
            }
        }
    }

    [DataContract]
    public class foto
    {
        [DataMember]
        public string filename { get; set; }

        [DataMember]
        public string title { get; set; }

        //[DataMember]
        //public string people { get; set; }

        [DataMember]
        public string events { get; set; }

        [DataMember]
        public string place { get; set; }

        [DataMember]
        public string type { get; set; }

        [DataMember]
        public string comment { get; set; }

        [DataMember]
        public int yeardate { get; set; }

        [DataMember]
        public string monthdate { get; set; }

        [DataMember]
        public double stars { get; set; }

        [DataMember]
        public string privates { get; set; }

        [DataMember]
        public string lat { get; set; }

        [DataMember]
        public string lon { get; set; }
    }
}